package models

import (
	_ "fmt"
	"gitchina/kly_service/data"
	"gitchina/kly_service/errors"
	"gitchina/kly_service/util"
	_ "github.com/astaxie/beego/orm"
	_ "io/ioutil"
	_ "os"
	_ "strconv"
	"time"
)

type Linebill struct {
	Id           ID     `json:"linebill_id"`
	StartArea    int    `json:"start_area"`
	StartAddr    string `json:"start_addr"`
	EndArea      int    `json:"end_area"`
	EndAddr      string `json:"end_addr"`
	ShipmentTime string `json:"shipment_time"`
	LinePubId    ID     `json:"line_pub_id"`
	EmpId        int    `json:"emp_id"`
	CargoName    string `json:"cargo_name"`
	CargoType    int    `json:"cargo_type"`
	CargoBulk    int    `json:"cargo_bulk"`
	CargoWeight  int    `json:"cargo_weight"`
	CargoCount   int    `json:"cargo_count"`
	Consignor    string `json:"consignor"`
	Consignee    string `json:"consignee"`
	Remark       string `json:"remark"`
	DeliveryType int    `json:"delivery_type"`
	State        int    `json:"linebill_state"`
}

type GetLinebillDetailRQ struct {
	Id ID `json:"linebill_id"`
}

type GetLinebillListRQ struct {
	QueryState string `json:"query_state"`
	PageNo     int    `json:"page_no"`
	PageSize   int    `json:"page_size"`
}

type LinebillListRS struct {
	TotalCount int            `json:"total_count"`
	List       []LinebillList `json:"linebill_list"`
}

type LinebillList struct {
	Id           ID     `json:"linebill_id"`
	ShipmentTime string `json:"shipment_time"`
	StartArea    int    `json:"start_area"`
	EndArea      int    `json:"end_area"`
	CargoType    int    `json:"cargo_type"`
	State        int    `json:"linebill_state"`
}

type UpdateLinebillStateRQ struct {
	Id    ID  `json:"linebill_id"`
	State int `json:"linebill_state"`
}

func (o Order) MakeLinebill(mbrId ID, rq *Linebill) (linebillId ID, err error) {
	var mId, pId, id int64
	var mbrRepo data.MemberRepo
	var orderRepo data.OrderRepo
	if _, _, _, mId, err = mbrId.Decode(); err != nil {
		err = errors.New(errors.MSG_Mbr_Invalid)
		return
	}

	if _, _, _, pId, err = rq.LinePubId.Decode(); err != nil {
		err = errors.New(errors.MSG_Logi_Invalid_Line_ID)
		return
	}

	if !mbrRepo.EnsureCargoOwner(int(mId)) {
		err = errors.New(errors.MSG_Mbr_Only_Cargo_Owner_Can_Make_Waybill)
		return
	}

	if err = o.checkValidLinebillRQ(int(pId), rq); err == nil {
		if id, err = orderRepo.MakeLinebill(&data.LinebillDto{
			OwnerId:      int(mId),
			EmpId:        rq.EmpId,
			LinePubId:    int(pId),
			ShipmentTime: rq.ShipmentTime,
			StartArea:    rq.StartArea,
			StartAddr:    rq.StartAddr,
			EndArea:      rq.EndArea,
			EndAddr:      rq.EndAddr,
			CargoName:    rq.CargoName,
			CargoType:    rq.CargoType,
			CargoBulk:    rq.CargoBulk,
			CargoWeight:  rq.CargoWeight,
			CargoCount:   rq.CargoCount,
			Consignee:    rq.Consignee,
			Consignor:    rq.Consignor,
			DeliveryType: rq.DeliveryType,
			Remark:       rq.Remark,
			State:        0,
		}); err != nil {
			util.GetLogger().Error("[model-MakeLinebill] - error:%s", err.Error())
			err = errors.New(errors.MSG_Order_Make_Waybill_Error)
			return
		} else {
			linebillId.Encode(ID_Shard, ID_Ver, ID_Linebill_Category, id)
		}
	}

	return
}

func (o Order) UpdateLinebillState(mbrId ID, rq *UpdateLinebillStateRQ) (err error) {
	var mId, linebillId int64
	var repo data.OrderRepo
	if _, _, _, mId, err = mbrId.Decode(); err != nil {
		err = errors.New(errors.MSG_Mbr_Invalid)
		return
	}

	if _, _, _, linebillId, err = rq.Id.Decode(); err != nil {
		err = errors.New(errors.MSG_Order_Invalid_Linebill)
		return
	}

	if rq.State == 1 || rq.State == 10 {
		if err = repo.UpdateLinebillState(int(linebillId), int(mId), rq.State); err != nil {
			util.GetLogger().Error("[model-UpdateLinebillState] - error:%s", err.Error())
			err = nil
		}
	} else {
		err = errors.New(errors.MSG_Order_Update_Linebill_Error)
	}

	return
}

func (o Order) GetLinebillList(mbrId ID, rq *GetLinebillListRQ) (rs LinebillListRS, err error) {
	var id int64
	var mbrType string
	var rowCount int
	var list []data.LinebillDto
	var mbrRepo data.MemberRepo
	var orderRepo data.OrderRepo

	if _, _, _, id, err = mbrId.Decode(); err != nil {
		err = errors.New(errors.MSG_Mbr_Invalid)
		return
	}
	if mbrType, err = mbrRepo.GetMemberType(int(id)); err != nil {
		util.GetLogger().Error("[model-GetLinebillList] - error:%s", err.Error())
	} else {
		if list, rowCount, err = orderRepo.GetLinebillList(int(id), rq.PageNo, rq.PageSize, rq.QueryState, mbrType); err == nil {
			linebills := make([]LinebillList, len(list))
			for idx, dto := range list {
				var linebillId ID
				linebillId.Encode(ID_Shard, ID_Ver, ID_Linebill_Category, int64(dto.Id))
				linebills[idx] = LinebillList{
					Id:           linebillId,
					ShipmentTime: dto.ShipmentTime,
					StartArea:    dto.StartArea,
					EndArea:      dto.EndArea,
					CargoType:    dto.CargoType,
					State:        dto.State,
				}
			}
			rs = LinebillListRS{TotalCount: rowCount, List: linebills}
		} else {
			util.GetLogger().Error("[model-GetLinebillList] - error:%s", err.Error())
			err = nil
		}
	}
	return
}

func (o Order) GetLinebillDetail(linebillId ID) (rs Linebill, err error) {
	var id int64
	var repo data.OrderRepo
	var dto data.LinebillDto
	_, _, _, id, err = linebillId.Decode()
	if err != nil {
		err = errors.New(errors.MSG_Logi_Invalid_Line_ID)
	} else {
		if dto, err = repo.GetLinebillDetail(int(id)); err == nil {
			var linePubId ID
			linePubId.Encode(ID_Shard, ID_Ver, ID_Line_Pub_Category, int64(dto.LinePubId))
			rs = Linebill{
				Id:           linebillId,
				StartArea:    dto.StartArea,
				StartAddr:    dto.StartAddr,
				EndArea:      dto.EndArea,
				EndAddr:      dto.EndAddr,
				ShipmentTime: dto.ShipmentTime,
				LinePubId:    linePubId,
				CargoName:    dto.CargoName,
				CargoType:    dto.CargoType,
				CargoBulk:    dto.CargoBulk,
				CargoWeight:  dto.CargoWeight,
				CargoCount:   dto.CargoCount,
				Consignor:    dto.Consignor,
				Consignee:    dto.Consignee,
				DeliveryType: dto.DeliveryType,
				Remark:       dto.Remark,
				State:        dto.State,
			}
		} else {
			util.GetLogger().Error("[model-GetLinebillDetail] - error:%s", err.Error())
			err = nil
		}
	}

	return
}

func (o Order) checkValidLinebillRQ(pubId int, rq *Linebill) (err error) {
	var shipmentTime time.Time
	var pub data.LinePubDetail
	var logiRepo data.LogisticsRepo
	//var orderRepo data.OrderRepo
	//check cargo type

	// if rq.StartArea%10000 == 0 || rq.EndArea%10000 == 0 {
	// 	err = errors.New(errors.MSG_Order_Invalid_Start_Or_End_Area)
	// 	return
	// }

	if len(rq.CargoName) == 0 {
		err = errors.New(errors.MSG_Order_Invalid_Cargo_Name)
		return
	}

	if pub, err = logiRepo.GetLinePubDetail(pubId); err == nil {
		rq.EmpId = pub.OwnerId
		// if pub.SrcCity == 0 {
		// 	if pub.SrcProvince != rq.StartArea-rq.StartArea%10000 {
		// 		err = errors.New(errors.MSG_Order_Invalid_Start_Area)
		// 		return
		// 	}
		// } else {
		// 	if pub.SrcCity != rq.StartArea {
		// 		err = errors.New(errors.MSG_Order_Invalid_Start_Area)
		// 		return
		// 	}
		// }

		// if pub.DestCity == 0 {
		// 	if pub.DestProvince != rq.EndArea-rq.EndArea%10000 {
		// 		err = errors.New(errors.MSG_Order_Invalid_End_Area)
		// 		return
		// 	}
		// } else {
		// 	if pub.DestCity != rq.EndArea {
		// 		err = errors.New(errors.MSG_Order_Invalid_End_Area)
		// 		return
		// 	}
		// }

		if len(rq.ShipmentTime) == 10 {
			if shipmentTime, err = time.Parse("2006-01-02", rq.ShipmentTime); err != nil {
				err = errors.New(errors.MSG_Order_Invalid_Shipment_Time)
				return
			}
		} else if len(rq.ShipmentTime) == 19 {
			if shipmentTime, err = time.Parse("2006-01-02 15:04:05", rq.ShipmentTime); err != nil {
				err = errors.New(errors.MSG_Order_Invalid_Shipment_Time)
				return
			} else {
				rq.ShipmentTime = shipmentTime.Format("2006-01-02 00:00:00")
			}
		} else {
			err = errors.New(errors.MSG_Order_Invalid_Shipment_Time)
		}
	} else {
		err = errors.New(errors.MSG_Order_Invalid_Carrier_Pub)
	}
	return err
}
